package com.file.parser.socialsecurity;

import com.file.bo.ResponseData;
import com.file.bo.socialsecurity.GuizhouIndividualRecordSheet;
import com.file.bo.socialsecurity.GuizhouInsuranceParticipation;
import com.file.constant.ErrorCode;
import com.file.parser.BasePdfParser;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.SpreadsheetDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class GuizhouSocialSecurityPdfParser extends BasePdfParser {

    public ResponseData<String> parseGuizhouSocialSecurityPdfParser(String daId, String filePath) {
        log.info("parseGuizhouSocialSecurityPdfParser started, daId:{}", daId);
        String json = null;
        try {
            if (filePath.contains("cbzm")) {
                GuizhouInsuranceParticipation GuizhouInsuranceParticipation = parseGuizhouInsuranceParticipation(filePath);
                json = JsonUtils.convertObjectToJson(GuizhouInsuranceParticipation);
            } else if (filePath.contains("qyd")) {
                GuizhouIndividualRecordSheet GuizhouIndividualRecordSheet = parseGuizhouIndividualRecordSheet(filePath);
                json = JsonUtils.convertObjectToJson(GuizhouIndividualRecordSheet);
            } else {
                log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseGuizhouSocialSecurityPdfToJson failed, new type not supported");
                return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
            }
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseGuizhouSocialSecurityPdfToJson failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseGuizhouSocialSecurityPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private void parseListToBO(List<List<String>> rowList, GuizhouInsuranceParticipation guizhouInsuranceParticipation) {
        String sectionName = "";
        List<GuizhouInsuranceParticipation.InsuranceParticipationRecord> insuranceParticipationRecordList = new ArrayList<>();

        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equals(cellList.get(0), "姓名")) {
                sectionName = "参保人情况";
            } else if (StringUtils.equals(cellList.get(0), "参保缴费情况")) {
                continue;
            } else if (StringUtils.equalsAny(cellList.get(1), "城乡居民基本养老保险","企业职工基本养老保险", "失业保险", "工伤保险")) {
                sectionName = "参保缴费情况";
            } else if (cellList.stream().allMatch(String::isEmpty)) {
                break;
            } else if (StringUtils.equals(cellList.get(0), "打印日期:")) {
                break;
            }
            switch (sectionName) {  //NOSONAR
                case "参保人情况":
                    guizhouInsuranceParticipation.setName(cellList.get(1));
                    guizhouInsuranceParticipation.setPersonalNumber(cellList.get(3));
                    guizhouInsuranceParticipation.setIdNo(cellList.get(5));
                    break;
                case "参保缴费情况":
                    GuizhouInsuranceParticipation.InsuranceParticipationRecord insuranceParticipationRecord = new GuizhouInsuranceParticipation.InsuranceParticipationRecord();
                    insuranceParticipationRecord.setInsured(cellList.get(1));
                    insuranceParticipationRecord.setCurrentInsuranceAgency(cellList.get(2));
                    insuranceParticipationRecord.setPaymentStatus(cellList.get(3));
                    insuranceParticipationRecord.setUnit(cellList.get(4));
                    Pattern pattern = Pattern.compile("(\\d{6}-\\d{6})(\\d{6}-\\d{6})");
                    String startAndEndTime = cellList.get(5).replaceAll(" ", "");
                    Matcher matcher = pattern.matcher(startAndEndTime);
                    if (matcher.find()) {
                        String range1 = matcher.group(1);
                        String range2 = matcher.group(2);
                        startAndEndTime = range1 + " " + range2;
                    }
                    insuranceParticipationRecord.setInsuranceParticipationStartAndEndTime(startAndEndTime);
                    insuranceParticipationRecord.setActualPaymentMonths(cellList.get(6));
                    insuranceParticipationRecord.setInterruptionMonths(cellList.get(7));
                    insuranceParticipationRecordList.add(insuranceParticipationRecord);
                    break;
            }
        }
        guizhouInsuranceParticipation.setInsuranceParticipationRecordList(insuranceParticipationRecordList);
    }

    private void parseListToBO(List<List<String>> rowList, GuizhouIndividualRecordSheet guizhouIndividualRecordSheet) {
        String sectionName = "";
        GuizhouIndividualRecordSheet.PersonalInformation personalInformation = new GuizhouIndividualRecordSheet.PersonalInformation();
        guizhouIndividualRecordSheet.setPersonalInformation(personalInformation);
        GuizhouIndividualRecordSheet.FirstEnrollmentDate firstEnrollmentDate = new GuizhouIndividualRecordSheet.FirstEnrollmentDate();
        personalInformation.setFirstEnrollmentDate(firstEnrollmentDate);
        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equals(cellList.get(0), "个 人 基 本 信 息")) {
                sectionName = "个人基本信息";
            } else if (StringUtils.equalsAny(cellList.get(0), "缴 费 情 况", "个人月缴费基数")) {
                continue;
            } else if (StringUtils.equals(cellList.get(0), "养老")) {
                sectionName = "缴费情况";
            } else if (StringUtils.equalsAny(cellList.get(0), "个 人 账 户 情 况", "基 本 养 老 保 险", "( 注:以社保最后一次计息为准)")) {
                continue;
            } else if (StringUtils.equals(cellList.get(0), "截至上年末个人账户累计储存额")) {
                sectionName = "个人账户情况";
            }
            switch (sectionName) { //NOSONAR
                case "个人基本信息":
                    if (StringUtils.equals(cellList.get(0), "姓名")) {
                        personalInformation.setName(cellList.get(1));
                        personalInformation.setUnit(cellList.get(3));
                        personalInformation.setSocialSecurityNumber(cellList.get(5));
                    } else if (StringUtils.equals(cellList.get(0), "首次参保日期")) {
                        cellList = rowList.get(i + 1);
                        firstEnrollmentDate.setInsuredPension(cellList.get(2));
                        firstEnrollmentDate.setInsuredUnemployment(cellList.get(3));
                        firstEnrollmentDate.setInsuredWorkRelatedInjury(cellList.get(5));
                    }
                    break;
                case "缴费情况":
                    if (StringUtils.equals(cellList.get(0), "养老")) {
                        GuizhouIndividualRecordSheet.PaymentStatus paymentStatus = new GuizhouIndividualRecordSheet.PaymentStatus();
                        GuizhouIndividualRecordSheet.MonthlyPersonalInsuranceBase monthlyPersonalInsuranceBase = new GuizhouIndividualRecordSheet.MonthlyPersonalInsuranceBase();
                        GuizhouIndividualRecordSheet.WorkInjuryInsurancePayment workInjuryInsurancePayment = new GuizhouIndividualRecordSheet.WorkInjuryInsurancePayment();
                        GuizhouIndividualRecordSheet.PensionInsurancePayment pensionInsurancePayment = new GuizhouIndividualRecordSheet.PensionInsurancePayment();
                        GuizhouIndividualRecordSheet.UnemploymentPaymentInfo unemploymentPaymentInfo = new GuizhouIndividualRecordSheet.UnemploymentPaymentInfo();
                        GuizhouIndividualRecordSheet.ActualPaymentMonths actualPaymentMonths = new GuizhouIndividualRecordSheet.ActualPaymentMonths();
                        paymentStatus.setMonthlyPersonalInsuranceBase(monthlyPersonalInsuranceBase);
                        paymentStatus.setWorkInjuryInsurancePayment(workInjuryInsurancePayment);
                        paymentStatus.setPensionInsurancePayment(pensionInsurancePayment);
                        paymentStatus.setUnemploymentPaymentInfo(unemploymentPaymentInfo);
                        paymentStatus.setActualPaymentMonths(actualPaymentMonths);
                        guizhouIndividualRecordSheet.setPaymentStatus(paymentStatus);
                        cellList = rowList.get(i + 1);
                        monthlyPersonalInsuranceBase.setInsuredPension(cellList.get(0));
                        monthlyPersonalInsuranceBase.setInsuredUnemployment(cellList.get(1));
                        monthlyPersonalInsuranceBase.setInsuredWorkRelatedInjury(cellList.get(2));
                        workInjuryInsurancePayment.setUnitPayment(cellList.get(3));
                        pensionInsurancePayment.setUnitPayment(cellList.get(4));
                        pensionInsurancePayment.setPersonalPayment(cellList.get(5));
                        unemploymentPaymentInfo.setUnitPayment(cellList.get(6));
                        unemploymentPaymentInfo.setPersonalPayment(cellList.get(7));
                        actualPaymentMonths.setInsuredPension(cellList.get(8));
                        actualPaymentMonths.setInsuredUnemployment(cellList.get(9));
                    }
                    break;
                case "个人账户情况":
                    if (StringUtils.equals(cellList.get(0), "截至上年末个人账户累计储存额")) {
                        GuizhouIndividualRecordSheet.PersonalAccountStatus personalAccountStatus = new GuizhouIndividualRecordSheet.PersonalAccountStatus();
                        GuizhouIndividualRecordSheet.BasicPensionInsurance basicPensionInsurance=new GuizhouIndividualRecordSheet.BasicPensionInsurance();
                        personalAccountStatus.setBasicPensionInsurance(basicPensionInsurance);
                        guizhouIndividualRecordSheet.setPersonalAccountStatus(personalAccountStatus);
                        cellList = rowList.get(i + 1);
                        basicPensionInsurance.setBasicPensionInsuranceAccumulation(cellList.get(0));
                        basicPensionInsurance.setCurrentYearPensionInsuranceRecord(cellList.get(1));
                        basicPensionInsurance.setCurrentYearPensionInsuranceExpenditure(cellList.get(2));
                        basicPensionInsurance.setCurrentYearPensionInsuranceInterest(cellList.get(3));
                        basicPensionInsurance.setPensionInsuranceAccumulationByYearEnd(cellList.get(5));
                    }
                    break;
            }
        }
    }

    private List<List<String>> parseFileToRowList(String filePath) {
        // 1. 读取文件
        File pdf = new File(filePath);

        //页面所有table的记录，每一个元素代表下面一条记录cellList
        List<List<String>> rowList = new ArrayList<>();

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf)) {
            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            SpreadsheetDetectionAlgorithm detectionAlgorithm = new SpreadsheetDetectionAlgorithm();
            Map<Integer, List<Rectangle>> pageNumber2RectangleListMap = new HashMap<>();//key为页的序号， value为对应的Rectangle的list

            // 4. 获取每页的PageIterator
            PageIterator pageIterator = objectExtractor.extract();

            // 5. 解析每页的Rectangle
            // 如果单页pdf中有多个Rectangle，则解析出来的List<Rectangle>会有多个对象
            while (pageIterator.hasNext()) {
                Page page = pageIterator.next();
                List<Rectangle> rectangleList = detectionAlgorithm.detect(page);
                if (rectangleList.size() > 0) {
                    pageNumber2RectangleListMap.put(page.getPageNumber(), rectangleList);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm extractionAlgorithm = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : pageNumber2RectangleListMap.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());
                Rectangle rectangle = null;

                List<Rectangle> rectangleList = entry.getValue();
                for (Rectangle r : rectangleList) {
                    double rectangleHeight = r.getHeight();
                    if (Double.compare(rectangleHeight, 0) > 0) {
                        rectangle = r;
                        break;
                    }
                }
                if (rectangle == null) {
                    throw new RuntimeException("rectangle is null.");
                }

                if (entry.getKey() > 1) {
                    rectangle.setTop(rectangle.getTop());
                }
                rectangle.setBottom(rectangle.getBottom() + 500);
                Page area = page.getArea(rectangle);

                // 如果每页有多个表格，解析每一个table
                List<Table> tableList = extractionAlgorithm.extract(area);
                for (Table table : tableList) {
                    for (int i = 0; i < table.getRowCount(); i++) {
                        List<String> cellList = new ArrayList<>();//一条记录，每个单元格占一个元素
                        for (int j = 0; j < table.getColCount(); j++) {
                            cellList.add(table.getCell(i, j).getText(false));
                        }
                        rowList.add(cellList);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        return rowList;
    }

    private GuizhouInsuranceParticipation parseGuizhouInsuranceParticipation(String filePath) {
        GuizhouInsuranceParticipation guizhouInsuranceParticipation = new GuizhouInsuranceParticipation();

        String pdfText = getPdfTextByStripper(filePath).replace(System.getProperty("line.separator", "\n"), StringUtils.EMPTY);
        String printTime = pdfText.substring(pdfText.lastIndexOf("打印日期：") + 5, pdfText.lastIndexOf("提示：")).replaceAll(" ", "");
        String prompt = pdfText.substring(pdfText.lastIndexOf("提示：") + 3, pdfText.lastIndexOf("（业务电子专用章）")).trim();
        guizhouInsuranceParticipation.setPrintTime(printTime);
        guizhouInsuranceParticipation.setPrompt(prompt);

        List<List<String>> rowList = parseFileToRowList(filePath);
        parseListToBO(rowList, guizhouInsuranceParticipation);
        return guizhouInsuranceParticipation;
    }

    private GuizhouIndividualRecordSheet parseGuizhouIndividualRecordSheet(String filePath) {
        GuizhouIndividualRecordSheet guizhouIndividualRecordSheet = new GuizhouIndividualRecordSheet();
        String pdfText = getPdfTextByStripper(filePath).replace(System.getProperty("line.separator", "\n"), StringUtils.EMPTY);
        String recordPeriod = "";
        Matcher matcher = Pattern.compile("([0-9]{4}年[0-9]{1,2}月至[0-9]{4}年[0-9]{1,2}月)").matcher(pdfText);
        if (matcher.find()) {
            recordPeriod = matcher.group(1);
        }

        guizhouIndividualRecordSheet.setRecordPeriod(recordPeriod);

        List<List<String>> rowList = parseFileToRowList(filePath);
        parseListToBO(rowList, guizhouIndividualRecordSheet);
        return guizhouIndividualRecordSheet;
    }

    public static void main(String[] args) {
        GuizhouSocialSecurityPdfParser guizhouSocialSecurityPdfParser = new GuizhouSocialSecurityPdfParser();
        String json, filePath;
        // 参保证明
        filePath = "D:\\data\\files\\socialsecurity\\贵州社保\\zd4akdkf1727884305426067456\\app-gjzwfw-dzsb_cbzm.pdf";
        json = guizhouSocialSecurityPdfParser.parseGuizhouSocialSecurityPdfParser("", filePath).getData();
        System.out.println("json = " + json);
        filePath = "D:\\data\\files\\socialsecurity\\贵州社保\\zd4akdkf1733879923520335872\\app-gjzwfw-dzsb_cbzm.pdf";
        json = guizhouSocialSecurityPdfParser.parseGuizhouSocialSecurityPdfParser("", filePath).getData();
        System.out.println("json = " + json);
        filePath = "D:\\data\\files\\socialsecurity\\贵州社保\\zd4akdkf1735098049554067456\\app-gjzwfw-dzsb_cbzm.pdf";
        json = guizhouSocialSecurityPdfParser.parseGuizhouSocialSecurityPdfParser("", filePath).getData();
        System.out.println("json = " + json);

        // 权益单
        filePath = "D:\\data\\files\\socialsecurity\\贵州社保\\zd4akdkf1735098049554067456\\app-gjzwfw-dzsb_qyd.pdf";
        json = guizhouSocialSecurityPdfParser.parseGuizhouSocialSecurityPdfParser("", filePath).getData();
        System.out.println("json = " + json);
        filePath = "D:\\data\\files\\socialsecurity\\贵州社保\\zd4akdkf1733879923520335872\\app-gjzwfw-dzsb_qyd.pdf";
        json = guizhouSocialSecurityPdfParser.parseGuizhouSocialSecurityPdfParser("", filePath).getData();
        System.out.println("json = " + json);
    }

}
